// MyCode.go
package main

/*
2020年8月25日上午测试成功。又经历了两天多的煎熬，终于成功了!!!!!!!!!!!!
刘永和
*/
import (
	"fmt"
)

const (
	// Type_FuncParm = 50
	// Type_FuncBody = 51
	Type_FuncCall = 52
	Type_Operator = 53
	// Type_Keyword  = 54
	// Type_Const    = 55
	Type_Variable = 56
	// Type_Bracket  = 57
	// Type_ForCycle = 58
	// Type_IfElse   = 59
	Type_Clause = 60

	TokenType_VarName  = 61
	TokenType_Keyword  = 62
	TokenType_Operator = 63
	TokenType_Brakets  = 64
)

func IsNumAndChar(char byte) bool {
	if (char >= 97 && char <= 122) || (char >= 65 && char <= 90) || (char == 95) || (char >= 48 && char <= 57) || char == '.' || char == '_' {
		return true
	}
	return false
}
func InKeywords(str string) bool {
	keywords := []string{"def", "for", "if", "else", "return", "import", "and", "or", "continue", "break", "while"}
	for _, s := range keywords {
		if s == str {
			return true
		}
	}
	return false
}
func findNextName(line string, start int) (string, int) { //find valid variable name
	for i := start; i < len(line); i++ { //skip those spaces,tabs and enter keys
		char := line[i]
		if char != ' ' && char != '\t' && char != '\n' {
			start = i
			break
		}
	}

	//fmt.Println(":::::next:", line[start:len(line)-1], "start:", start)
	for i := start; i < len(line); i++ { //search for a valid mark in the line
		var char byte
		char = line[i]
		//如果遇到了减号，但前一个字符是e,e前面还有数字，则把减号当作科学计数法
		if i > start+1 && char == '-' && (line[i-1] == 'e' || line[i-1] == 'E') && (line[i-2] >= '0' && line[i-2] <= '9') {
			continue
		}
		if !IsNumAndChar(char) { //只要不是数字或者字符，则直接返回
			//fmt.Println("return:", line[start:i], i)
			return line[start:i], i
		}

		if i > start && (line[start] < '0' || line[start] > '9') && line[i] == '.' { //如果遇到了小数点，但前一个字符不是数字
			return line[start:i], i
		}
	}
	//接下来需要从含小数点的数字和含.的字符串进行区分，含点的字符串应该把.当作是运算符

	//panic("not implemented")

	return line[start:], len(line)
}

//查找下一个被引号括起来的字符串,其中引号的下标刚好是start
func findNextString(line string) (string, int) {
	//0处是引号，所以要避开它

	for start := 1; start < len(line); start++ {
		if line[start] == line[0] && line[start-1] != '\\' {
			return line[1:start], start + 1
		}
	}
	panic("No string is found")
}
func findNextOperator(line string, start int) (string, int) { //find valid variable name or number or operator

	for i := start; i < len(line); i++ { //skip those spaces,tabs and enter keys
		char := line[i]
		if !(char == ' ' || char == '\t' || char == '\n') {
			start = i
			break
		}
	}
	if start < len(line)-3 && IsOperator(line[start:start+3]) { //如果三个字符连起来的字符属于一个运算符则返回
		//fmt.Println("symbol", start, " ", line[start:start+3])
		return string(line[start : start+3]), start + 3
	}

	if start < len(line)-2 && IsOperator(line[start:start+2]) { //如果二个字符连起来的字符属于一个运算符则返回
		return string(line[start : start+2]), start + 2
	}

	if start < len(line)-1 && IsOperator(line[start:start+1]) { //如果一个字符连起来的字符属于一个运算符则返回
		return string(string(line[start])), start + 1
	}
	return "", start

}
func findNextChar(line string, start int) (byte, int) {
	for i := start; i < len(line); i++ {
		char := line[i]
		if !(char == ' ' || char == '\t') {
			start = i
			break
		}
	}
	return line[start], start
}
func IsValidVarName(str string) bool {
	for i := 0; i < len(str); i++ {
		if !IsNumAndChar(str[i]) {
			return false
		}
	}
	if str == "," {
		return false
	}
	return true
}
func IsOperator(str string) bool {
	operators := []string{"[]", "^", "+", "-", "*", "/", "==", "!=", ">", ">=", "<", "<=", "not", "and", "or", "=", "+=", ":="}
	for _, s := range operators {
		if s == str {
			return true
		}
	}
	return false
}

// func (code *MyCode) Scan(line string, start int) (int, bool) {

// 	clause := new(Clause)
// 	code.clauses = append(code.clauses, clause)
// 	var name string
// 	for each := 0; each < 30; each++ {
// 		if start >= len(line) {
// 			break
// 		}
// 		//read in another name
// 		// fmt.Println("---start:", start)
// 		name, start = findNextName(line, start)
// 		// fmt.Print("line:", line)
// 		// fmt.Println("start:", start, "name:", name)
// 		flag := TokenType_VarName

// 		if name != "" { //if found a valid name, print it out
// 			//fmt.Println("ii=", name, line)
// 			if InKeywords(name) {
// 				//	code.EvalKeyWord(name)
// 				flag = TokenType_Keyword

// 			} else if IsValidVarName(name) {
// 				flag = TokenType_VarName
// 				//fmt.Println(name)
// 				//	code.EvalName(name)
// 			} else if IsOperator(name) {
// 				flag = TokenType_Operator
// 			}
// 			//fmt.Println(flag)
// 			//fmt.Println(name)
// 			code.AddToken(name)
// 			//if name == "for" {
// 			//fmt.Println(name)
// 			//}
// 		}

// 		if flag == TokenType_Keyword {
// 			name, start = findNextName(line, start)
// 			//fmt.Println(name)
// 			code.AddToken(name)
// 			continue
// 		}
// 		//readin another operator
// 		char2, end2 := findNextOperator(line, start)
// 		if char2 != "" {
// 			start = end2
// 			//fmt.Println(char2)
// 			code.AddToken(char2)
// 			continue
// 		}
// 		//找到一个操作符后，下面不一定就是一个括号这样的符号，还有可能是变量，所以会导致错误
// 		// if no operator is found, to test whether is other symbols
// 		var char byte
// 		var end int
// 		if start < len(line) {
// 			char, end = findNextChar(line, start)
// 			start = end + 1
// 		} else {
// 			break
// 		}
// 		if char == '{' {
// 			code.Hvalue += 1
// 			code.AddToken("{")
// 			continue
// 		} // end (
// 		if char == '}' {
// 			code.Hvalue -= 1
// 			code.AddToken("}")
// 			continue
// 		} // end (
// 		if char == '(' {
// 			code.Cvalue += 1
// 			code.AddToken("(")
// 			continue
// 		} // end (

// 		if char == ',' {

// 			code.AddToken(",")

// 			continue
// 		} //end ,

// 		if char == ')' {
// 			code.Cvalue -= 1
// 			code.AddToken(")")
// 			continue
// 		} // end )
// 		if char == '\n' || char == ';' {
// 			code.AddToken("\n")
// 			continue
// 		}

// 		if char == '\n' || char == ';' || char == 0 {
// 			continue
// 		}

// 		_, err := strconv.ParseFloat(name, 64)
// 		if err == nil {
// 			code.AddToken(name)
// 			continue
// 		}

// 		//fmt.Println(varname, "and other ones", string(char), char)
// 	} //end for
// 	return start, true
// }

func findNextSymbol(tokens []string, str string) int {
	for i, each := range tokens {
		if str == each {
			return i
		}
	}
	return -1
}

func getPriority(op string) int {
	if op == "=" || op == "+=" || op == "-=" || op == "*=" || op == "/=" || op == ":=" {
		return 0
	}
	if op == "or" {
		return 1
	}
	if op == "and" {
		return 2
	}
	if op == "not" {
		return 3
	}
	if op == ">" || op == "<" || op == ">=" || op == "<=" || op == "==" || op == "!=" {
		return 4
	}
	if op == "+" || op == "-" {
		return 5
	}
	if op == "*" || op == "/" || op == "%" || op == "//" {
		return 6
	}

	if op == "^" || op == "!" {
		return 7
	}
	if op == "[]" {
		return 8
	}
	// if op == "." {
	// 	return 8
	// }
	panic("not a correct operator")
	return 0
}
func getOperFunc(str string) string {
	switch str {
	case "+":
		{
			return "add"
		}
	case "-":
		{
			return "sub"
		}
	case "*":
		{
			return "mul"
		}
	case "/":
		{
			return "div"
		}
	case "^":
		{
			return "pow"
		}
	case "+=":
		{
			return "addset"
		}
	case "=":
		{
			return "assign"
		}
	case "not":
		{
			return "not"
		}
	case "and":
		{
			return "and"
		}
	case "or":
		{
			return "or"
		}
	case ">":
		{
			return "larger"
		}
	case "<":
		{
			return "smaller"
		}
	case ">=":
		{
			return "largEq"
		}
	case "<=":
		{
			return "smalEq"
		}

	case "==":
		{
			return "equal"
		}
	case "!=":
		{
			return "unequal"
		}

	case "[]":
		{
			return "getItem"
		}
	case ".":
		{
			return "member"
		}

	}
	fmt.Println("operator:", str)
	panic("not implemented:" + str)
}

//把formula解析成一个有效的函数调用子句
func HandleFormula(formula []*DrClause) *DrClause {
	if len(formula) == 1 {
		return formula[0]
	}
	if len(formula) == 0 {
		panic("formula cannot be length of 0")
	}
	//fmt.Println("In formula:", formula[0])
	//扫描formula，先找出所有的operator,找出优先级最大的那个
	prior := -1
	loc := 0
	for i, value := range formula {
		vari := value.getVariable()
		if IsOperator(vari) {
			//			fmt.Println(i, vari)
			if prior < getPriority(vari) {
				prior = getPriority(vari)
				loc = i
			}
		}
	}
	op := formula[loc].getVariable()
	//if op == "=" && formula[loc+1].getVariable() == "add" {
	//	fmt.Println(op)
	//}

	clause := new(DrClause)
	clause.ClauseType = ClauseType_SINGLE
	clause.funcName = getOperFunc(op)
	//如果是单目 运算符，加一个参数
	if op == "not" {
		clause.AddParameter(formula[loc+1])
	}
	//位于等号后面的减号
	if (formula[0].funcName == "-" && op == "-") || (formula[0].funcName == "+" && op == "+") {
		clause := new(DrClause)
		clause.ClauseType = ClauseType_CONSTANT
		clause.Type = TypeNum
		clause.funcName = "0"
		temp := make([]*DrClause, 0, 10)
		temp = append(temp, clause)
		formula = append(temp, formula...)
		//fmt.Println(formula)
		loc += 1
	}

	//如果是双目运算符，加两个参数
	//	pcount := 0
	var formula1 []*DrClause
	if op == "+" || op == "-" || op == "*" || op == "/" || op == "^" || op == "+=" || op == "=" || op == "and" || op == "or" || op == ">" || op == "<" || op == ">=" || op == "<=" || op == "==" || op == "!=" || op == "[]" || op == "." { //其他的暂时也不写了
		//fmt.Println("In formula:", formula[loc-1].funcname, formula[loc+1].funcname)
		if !(formula[loc-1].getVariable() == "=" && op == "-") {
			//printFormula(formula)
			clause.AddParameter(formula[loc-1])
			clause.AddParameter(formula[loc+1])

			if loc-1 > 0 { //如果当前位置之前还有内容，则之前的当作一个formula处理
				formula1 = formula[:loc-1]
			}
			formula1 = append(formula1, clause)
			if loc+2 < len(formula) { //如果当前位置之后还有内容，则之后的当作一个formula处理
				formula1 = append(formula1, formula[loc+2:]...)
			}
		}
	}

	//	fmt.Println("Formula:")
	//	printFormula(formula1)
	if len(formula1) > 1 {
		return HandleFormula(formula1)

	} else {
		//		clause.Print()
		return clause
	}

}
func printFormula(aaa []*DrClause) {
	//	fmt.Print("formula:")
	for _, v := range aaa {
		fmt.Print(v.funcName, " ")
	}
	fmt.Println()
}
func cutSquarePair(tokens []string) []string {
	count := 1
	var end int
	for i := 0; i < len(tokens); i++ {
		if tokens[i] == "[" {
			count += 1
		}
		if tokens[i] == "]" {
			count -= 1
		}
		if count == 0 {
			end = i
			break
		}
	}
	return tokens[0:end]
}
func findToken(token string, tokens []string) int {
	pos := -1
	for i := 0; i < len(tokens); i++ {
		if token == tokens[i] {
			pos = i
			break
		}
	}
	return pos
}

//解析独立子句，包括赋值号、逗号、各种运算符和圆括号。不包括for、if-else、def之类的关键词

func (code *DrCode) ParseClause1(tokens []string) (*DrClause, []string) {
	var result *DrClause
	result = new(DrClause)
	result.ClauseType = ClauseType_SINGLE

	var formula []*DrClause
	var token string
	tokenList := tokens[0:]
	//i := start
	var pair *DrClause

	count := 0 //用于对冒号出现的状态记数，当遇到一个冒号时count+1，遇到一个逗号且count>0时count-1
	for {
		if len(tokenList) <= 0 { //处理清空formula，完成pair，把pair加入result
			if count > 0 { //处理与下标有关的内容
				count -= 1
				cl := HandleFormula(formula)
				pair.AddParameter(cl)
				if len(pair.parameters) != 2 {
					panic("incorrect length of pair")
				}
				result.AddParameter(pair)
				result = upgradeClause(result)
				return result, nil
			} else {
				cl := HandleFormula(formula)
				result.AddParameter(cl)
				result = upgradeClause(result)
				return result, nil
			}

		}
		token = tokenList[0]
		if token == "\n" || token == "{" || token == "}" {
			cl0 := HandleFormula(formula)
			result.AddParameter(cl0)
			result = upgradeClause(result)

			return result, tokenList
		}
		token := tokenList[0]
		tokenList = tokenList[1:]
		if token == "," { //解析后续的参数，加入已有的clause
			//先把前面收集到的formula解析后，再解析','之后的内容
			cl0 := HandleFormula(formula)
			if count > 0 { //凡是前面有没处理完的冒号，进入这里处理
				//fmt.Println(count, token, tokenList, pair)
				pair.parameters = append(pair.parameters, cl0)
				count -= 1
				if len(pair.parameters) != 2 {
					panic("incorrect Pair")
				}
				result.AddParameter(pair)
			} else { //不涉及冒号的这样处理
				result.AddParameter(cl0)
			}
			//与逗号后面的内容是并列的
			//fmt.Print("遇到了逗号，已将逗号前面的表达式处理过了，如：")
			//			printFormula(formula)
			formula = []*DrClause{}
			continue
		}
		if token == "," { //解析后续的参数，加入已有的clause
			//先把前面收集到的formula解析后，再解析','之后的内容
			cl0 := HandleFormula(formula)
			if count > 0 { //凡是前面有没处理完的冒号，进入这里处理
				//fmt.Println(count, token, tokenList, pair)
				pair.parameters = append(pair.parameters, cl0)
				count -= 1
				if len(pair.parameters) != 2 {
					panic("incorrect Pair")
				}
				result.AddParameter(pair)
			} else { //不涉及冒号的这样处理
				result.AddParameter(cl0)
			}
			//与逗号后面的内容是并列的
			//fmt.Print("遇到了逗号，已将逗号前面的表达式处理过了，如：")
			//			printFormula(formula)
			formula = []*DrClause{}
			continue
		}
		if token == ":" { //解析后续的参数，加入已有的clause
			//先把前面收集到的formula解析后，再解析','之后的内容
			pair = new(DrClause)
			pair.funcName = "pair"
			pair.ClauseType = ClauseType_SINGLE
			cl0 := HandleFormula(formula)
			pair.parameters = append(pair.parameters, cl0)
			count += 1
			//result.AddParameter(cl0) //与逗号后面的内容是并列的
			//fmt.Print("遇到了逗号，已将逗号前面的表达式处理过了，如：")
			//			printFormula(formula)
			formula = []*DrClause{}
			continue
		}

		if token[0] == '.' && IsValidVarName(token[1:]) && tokenList[0] == "(" {
			tokenList = tokenList[1:]
			code.bStack.push(Type_FuncCall)
			clause, tokens2 := code.ParseClause1(tokenList)
			tokenList = tokens2
			cl := new(DrClause)
			cl.ClauseType = ClauseType_SINGLE
			cl.funcName = token
			n := len(formula)
			cl.AddParameter(formula[n-1])
			cl.parameters = append(cl.parameters, clause.parameters...)
			formula[n-1] = cl
			continue

		}
		// if token == "." && IsValidVarName(code.tokenList[0]) && code.tokenList[1] == "(" {
		// 	//把formula中最后一项降级为新clause的第一个参数，新clause即为member函数，
		// 	n := len(formula)
		// 	cl_get_member := new(DrClause)
		// 	cl_get_member.funcName = "member"
		// 	cl_get_member.ClauseType = ClauseType_SINGLE
		// 	cl_get_member.AddParameter(formula[n-1])

		// 	funcName := code.tokenList[0]
		// 	tempClause := new(DrClause)
		// 	tempClause.ClauseType = ClauseType_CONSTANT
		// 	tempClause.Type = TypeString
		// 	tempClause.funcName = funcName
		// 	cl_get_member.AddParameter(tempClause)
		// 	//把点号后面的方法名作为另一个参数

		// 	cl_method := new(DrClause)
		// 	cl_method.ClauseType = ClauseType_SINGLE
		// 	cl_method.AddParameter(cl_get_member)
		// 	//把括号内部的内容当作新函数调用来处理
		// 	code.tokenList = code.tokenList[2:]
		// 	code.bStack.push(Type_FuncCall)
		// 	clause := code.ParseClause2()
		// 	cl_method.funcName = funcName
		// 	cl_method.parameters = append(cl_method.parameters, clause.parameters...)

		// 	formula[n-1] = cl_method
		// 	continue

		// }

		if len(tokenList) > 0 && IsValidVarName(token) && tokenList[0] == "(" { //遇到 funcname(),处理至下一个")",在函数内部新建一个clause并赋好参数，出来时赋函数名称
			//fmt.Println("现在开始进入新函数的调用了:", tokens[i], tokens[i+1])
			code.bStack.push(Type_FuncCall)
			tokenList = tokenList[1:]
			clause, tokens2 := code.ParseClause1(tokenList) //&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
			tokenList = tokens2
			clause.funcName = token
			//fmt.Println("本层函数调用结束：", clause.funcname)
			formula = append(formula, clause)
			continue
		}
		//var clause *Clause
		if token == "(" { //'('表明开始了一个新的调用，从当前括号‘(’开始到下一个‘)’结束，找到若干个逗号分隔的clause，共同作为当前调用的参数
			//fmt.Println("现在开始进入新括号的调用了:", tokens[i], tokens[i+1])
			code.bStack.push(Type_Clause)
			clause, tokens2 := code.ParseClause1(tokenList) //&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
			tokenList = tokens2
			clause = upgradeClause(clause)
			//fmt.Println("本层括号调用结束：", clause.funcname, i, tokens[i])
			formula = append(formula, clause)
			continue
		}
		if token == ")" { //遇到递归返回标志了  ，但是分两种情况
			top := code.bStack.pop()
			if top == Type_Clause { //如果是普通括号，返回值 是一个直接的clause
				//printFormula(formula)
				cls := HandleFormula(formula)
				result.AddParameter(cls)
			} else {
				//如果是带函数的括号，返回值是作为函数的其中一个参数
				if len(formula) > 0 {
					//printFormula(formula)
					//					result.print()
					cl := HandleFormula(formula)
					if count > 0 { //凡是前面有没处理完的冒号，进入这里处理
						//fmt.Println(count, token, tokenList, pair)
						pair.parameters = append(pair.parameters, cl)
						count -= 1
						if len(pair.parameters) != 2 {
							panic("incorrect Pair")
						}
						result.AddParameter(pair)
					} else { //不涉及冒号的这样处理
						result.AddParameter(cl)
					}
				}
			}

			//i += 1
			//fmt.Println("现在要从", tokens[i], "返回上级，下一个符号是", tokens[i+1], "现在所在的函数看下面吧")
			if IsNumber(result.funcName) && result.ClauseType == ClauseType_VAR {
				panic("clause type incorrect")
			}
			return result, tokenList
		}
		if token == "=" {
			cl := HandleFormula(formula) //把等号之前收集好的公解析为clause
			result.AddParameter(cl)      //把解析好的clause把为参数添加到result中
			result = upgradeClause(result)
			if result.funcName == "getItem" {
				result.funcName = "setItem"
				cl2 := code.ParseClause2()
				result.AddParameter(cl2)
			} else {
				temp := result
				result = new(DrClause) //使用新建的result
				result.ClauseType = ClauseType_SINGLE
				result.AddParameter(temp)
				result.funcName = "assign"
				cl2 := code.ParseClause2()
				result.AddParameter(cl2)
			}
			return result, tokenList
		}
		if IsOperator(token) { //如果是这种情况，就需要扫描后续的同括号内的表达式
			cl := new(DrClause)
			cl.ClauseType = ClauseType_VAR
			cl.setVariable(token)
			formula = append(formula, cl)
			continue
		}
		if IsNumber(token) {
			//			fmt.Println("enter_5:", tokens[i])
			cl := new(DrClause)
			cl.setConstant(token)
			formula = append(formula, cl)
			continue
		}
		if IsValidVarName(token) {
			cl := new(DrClause)
			cl.ClauseType = ClauseType_VAR
			cl.setVariable(token)
			//			cl.print()
			formula = append(formula, cl)
			//printFormula(formula)

			//			fmt.Println("-", i, "-", len(tokens), "-", tokens[i])
			continue
		}
		// if token == "=" {
		// 	cl := HandleFormula(formula) //把等号之前收集好的公解析为clause
		// 	result.AddParameter(cl)      //把解析好的clause把为参数添加到result中
		// 	result = upgradeClause(result)
		// 	temp := result
		// 	result = new(DrClause) //使用新建的result
		// 	result.ClauseType = ClauseType_SINGLE
		// 	result.AddParameter(temp)
		// 	result.funcName = "assign"
		// 	cl2 := code.ParseClause2()
		// 	result.AddParameter(cl2)
		// 	return result, tokenList
		// }

		if token == "'" || token == "\"" {
			cl := new(DrClause)

			cl.Type = TypeString
			cl.ClauseType = ClauseType_CONSTANT
			str0 := tokenList[0]
			tokenList = tokenList[1:]
			cl.Type = TypeString
			cl.Value = str0
			cl.funcName = str0
			sss := tokenList[0]
			tokenList = tokenList[1:]
			if sss != token {
				panic("A quotation mark is required, but encountered a " + sss)
			}
			formula = append(formula, cl)
			continue
		}
		if token == "[" {
			tokenList2 := cutSquarePair(tokenList)
			tokenList = tokenList[len(tokenList2)+1:]
			//fmt.Println(tokenList2)
			opCL := new(DrClause) //放置符号[]的clause
			opCL.ClauseType = ClauseType_VAR
			//opCL.setVariable("[]")
			formula = append(formula, opCL)
			tempCL, _ := code.ParseClause1(tokenList2) //放置下标的clause
			//fmt.Println(tokens2)
			formula = append(formula, tempCL)
			continue
		}

		if token == "\n" {
			fmt.Println("\n is encountered")
			break
		}
	}

	r := HandleFormula(formula)
	if IsNumber(r.funcName) && r.ClauseType == ClauseType_VAR {
		panic("clause type incorrect")
	}
	//	r.Print()
	return r, tokenList
}

//解析独立子句，包括赋值号、逗号、各种运算符和圆括号。不包括for、if-else、def之类的关键词
func upgradeClause(result *DrClause) *DrClause {
	if result.funcName == "" {
		if len(result.parameters) == 1 { //如果clause没有函数名字，且参数只有一个，那就将参数直接升级为clause
			result = result.parameters[0]
		} else if len(result.parameters) > 1 {
			result.funcName = "tuple"
		}
	}
	return result
}
